using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using DigitalTrainSuite;
using DigitalTrainSuite.Canvas;

namespace DigitalTrainSuite.UserControls
{
	public enum CanvasMode
	{
		Controller,
		Designer,
		Layout
	}

	public partial class UserControlLayout : UserControl
	{
	#region private members

		private Dictionary<int, UserControlSensorController> sensorControls;
		private APIControl controller;
		private SensorDriver sensorNetDriver;
		private bool enableControls = false;
		private bool enableEdit = false;
		private bool viewAddresses = true;
		private DataSetLayout.TrackRow placingTrack;
		private DoublePoint snapOffset;
		private bool placingTrackVisible = false;
		private bool placingTrackFreeze = false;
		private double drawingScale = 5;
		private DataSetLayout data;
		private bool ready = false;
		private CanvasMode mode = CanvasMode.Controller;
		private bool viewControls = false;
		private Grid snapGrid;
		private int snapRes = 50;
		private double zoom = 20.0;
		private DoublePoint zeroOffset = new DoublePoint(0, 0);

		#endregion

	#region public methods

		public UserControlLayout()
		{
			InitializeComponent();
			this.snapGrid = new Grid((int)(this.drawingScale * this.Size.Width / this.snapRes), (int)(this.drawingScale * this.Size.Height / this.snapRes), this.snapRes);
			this.sensorControls = new Dictionary<int,UserControlSensorController>();
		}

		public double gridsSnapRes()
		{
			return this.snapGrid.SnapRes;
		}

		public void loadLayout()
		{
			if (!this.ready) return;

			this.Controls.Clear();

			foreach (DataSetLayout.TurnoutControlRow row in this.data.TurnoutControl.Rows)
			{
				UserControlTurnoutController control;
				if (this.mode == CanvasMode.Controller)
				{
					control = new UserControlTurnoutController(row.turnoutAddress, new Point((int)(row.locationX / this.drawingScale), (int)(row.locationY / this.drawingScale)), this.controller.controllSwitch, (RotateFlipType)row.rotation, (TurnoutPosition)row.position);
				}
				else
				{
					control = new UserControlTurnoutController(row.turnoutAddress, new Point((int)(row.locationX/this.drawingScale), (int)(row.locationY/this.drawingScale)), (RotateFlipType)row.rotation, (TurnoutPosition)row.position);
				}
				control.Mode = this.Mode;
				control.deleteControl += new DeleteControl(control_deleteControl);
				this.Controls.Add(control);
			}
			foreach (DataSetLayout.RFIDSensorRow row in this.data.RFIDSensor.Rows)
			{
				UserControlSensorController control;
				if (this.mode == CanvasMode.Controller)
				{
					control = new UserControlSensorController(row.sensorId, this.sensorNetDriver, this.controller);
					control.Location = new Point(row.locationX, row.locationY);
					control.Rotation = (RotateFlipType)(row.rotation);
					control.SlowSpeed = row.slowSpeed;
					control.GoSpeed = row.goSpeed;
					control.DirectionATrainId = row.directionATrain;
					control.DirectionBTrainId = row.directionBTrain;
					control.DirectionASensorId = row.directionASensorId;
					control.DirectionBSensorId = row.direcitonBSensorId;
					control.SensorControls = this.sensorControls;
					try
					{
						this.sensorControls.Add(row.sensorId, control);
						this.Controls.Add(control);
					}
					catch (Exception e)
					{
					}
					
				}
				else
				{
					control = new UserControlSensorController();
					control.SensorId = row.sensorId;
					control.Location = new Point(row.locationX, row.locationY);
					control.Rotation = (RotateFlipType)(row.rotation);
					control.SlowSpeed = row.slowSpeed;
					control.GoSpeed = row.goSpeed;
					control.DirectionATrainId = row.directionATrain;
					control.DirectionBTrainId = row.directionBTrain;
					control.DirectionASensorId = row.directionASensorId;
					control.DirectionBSensorId = row.direcitonBSensorId;
					this.Controls.Add(control);
				}
			}

			this.SnapResolution = this.snapRes;
		}

		public void saveLayout(DataSetLayout data)
		{
			if (!this.ready)
			{
				MessageBox.Show("Cannot save layout.\nCanvas not ready", "Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			foreach ( Control thisControl in this.Controls)
			{
				if (thisControl is UserControlTurnoutController)
				{
					UserControlTurnoutController control = (UserControlTurnoutController)thisControl;
					data.TurnoutControl.AddTurnoutControlRow(control.SwitchID, control.Location.X*this.drawingScale, control.Location.Y*this.drawingScale, control.Position.GetHashCode(), control.Rotation.GetHashCode());
				}
				else if (thisControl is UserControlSensorController)
				{
					UserControlSensorController control = (UserControlSensorController)thisControl;
					data.RFIDSensor.AddRFIDSensorRow(control.SensorId, control.Location.X, control.Location.Y, control.Rotation.GetHashCode(), control.SlowSpeed, control.GoSpeed, control.DirectionASensorId, control.DirectionBSensorId, control.DirectionATrainId, control.DirectionBTrainId);
				}
			}
		} 

		#endregion

	#region public properties

		public APIControl Controller
		{
			get { return this.controller; }
			set { this.controller = value; this.updateReadyState(); }
		}

		public SensorDriver SensorNetDriver
		{
			get { return sensorNetDriver; }
			set { this.sensorNetDriver = value; }
		}

		public DataSetLayout.TrackRow PlacingTrack
		{
			get { return this.placingTrack; }
			set
			{
				if (this.ready)
				{
					this.placingTrack = value;
					this.snapOffset = new DoublePoint(0, 0);
				}
				else
				{
					this.placingTrack = null;
				}
			}
		}

		public DataSetLayout Data
		{
			get { return this.data; }
			set
			{
				this.data = value;
				this.updateReadyState();
				this.loadLayout();
			}
		}

		public CanvasMode Mode
		{
			get { return this.mode; }
			set { this.mode = value; this.updateReadyState(); }
		}

		public int SnapResolution
		{
			get { return this.snapRes; }
			set
			{
				snapRes = value;
				this.snapGrid = new Grid((int)(this.drawingScale * this.Size.Width / value), (int)(this.drawingScale * this.Size.Height / value), value);
				if (this.ready)
				{
					foreach (DataSetLayout.TrackRow row in this.data.Track.Rows)
					{
						this.snapGrid.addTrack(row);
					}
				}
			}
		}

		public double Zoom
		{
			get { return zoom; }
			set
			{
				this.zoom = value;
				this.drawingScale = 1.0 / (this.zoom / 100.0);
				this.loadLayout();
				this.Invalidate();
			}
		}

		public double DrawingScale
		{
			get { return this.drawingScale; }
			set
			{
				this.drawingScale = value;
				this.zoom = (1.0 / this.drawingScale) * 100.0;
				this.Invalidate();
			}
		}

		public bool ViewControls
		{
			get { return this.viewControls; }
			set
			{
				foreach (Control control in this.Controls)
				{
					control.Visible = value;
				}
				this.viewControls = value;
			}
		}

		public bool EnableEdit
		{
			get { return this.enableEdit; }
			set
			{
				foreach (Control control in this.Controls)
				{
					if (control is IMoveableUserControl) ((IMoveableUserControl)control).Movable = value;
				}
			}
		}

		public bool ViewAddresses
		{
			get { return this.viewAddresses; }
			set
			{
				foreach (Control thisControl in this.Controls)
				{
					if (thisControl is UserControlTurnoutController)
					{
						((UserControlTurnoutController)thisControl).AddressVisible = value;
					}
					if (thisControl is UserControlSensorController)
					{
						// do stuff
					}
				}				 
			}
		}

		public bool EnableControls
		{
			get { return this.enableControls; }
			set
			{
				foreach (Control thisControl in this.Controls)
				{
					if (thisControl is UserControlTurnoutController)
					{
						((UserControlTurnoutController)thisControl).EnableControl = value;
					}
					if (thisControl is UserControlSensorController)
					{
						// do stuff
					}
				}
				this.enableControls = value;
			}
		}

		private Tools selectedTool = Tools.MoveTrack;

		public Tools SelectedTool
		{
			get { return selectedTool; }
			set 
			{ 
				selectedTool = value;
				switch (value)
				{
					case Tools.Delete:
						this.Cursor = new Cursor("Resources/CursorDelete.cur");
						this.placingTrackVisible = false;
						this.placingTrack = null;
						break;
					case Tools.MoveTrack:
						this.Cursor = Cursors.Default;
						this.placingTrackVisible = false;
						this.placingTrack = null;
						break;
					default:
						this.Cursor = Cursors.Default;
						break;
				}
			}
		}

		private bool snapToParts = false;

		public bool SnapToParts
		{
			get { return snapToParts; }
			set 
			{ 
				snapToParts = value; 
			}
		}



		#endregion

	#region private methods

		private void updateReadyState()
		{
			this.ready = false;
			switch (this.mode)
			{
				case CanvasMode.Controller:
					if (this.controller != null && this.data != null) this.ready = true;
					break;
				case CanvasMode.Designer:
					if (this.data != null && this.snapGrid != null) this.ready = true;
					break;
				case CanvasMode.Layout:
					this.ready = false;
					break;
				default:
					this.ready = false;
					break;
			}
		} 

		#endregion

	#region private event handlers

		private void UserControlLayout_MouseMove(object sender, MouseEventArgs e)
		{
			if (this.placingTrack != null && !this.placingTrackFreeze)
			{
				DoublePoint point;

				this.placingTrackVisible = true;
				this.placingTrack.locationX = e.X * this.drawingScale;
				this.placingTrack.locationY = e.Y * this.drawingScale;
				/*DoublePoint point = this.snapGrid.snapTo(this.drawingScale * e.X, this.drawingScale * e.Y);
				if (point != null)
				{
					this.placingTrack.locationX = point.X;
					this.placingTrack.locationY = point.Y;
					this.Invalidate();
					return;
				}*/
				if (this.SnapToParts)
				{
					List<DoublePoint> points = EndPoint.findEndPoints(this.placingTrack);

					foreach (DoublePoint p in points)
					{
						point = this.snapGrid.snapTo(p.X, p.Y);
						if (point != null)
						{
							this.snapOffset = new DoublePoint((point.X - p.X), (point.Y - p.Y));
							this.Invalidate();
							return;
						}
						else
						{
							this.snapOffset = this.zeroOffset;
						}
					}
				}

				this.Invalidate();
				return;
			}
		}

		private void UserControlLayout_Paint(object sender, PaintEventArgs e)
		{
			if (!this.ready) return;
			DrawTracks drawer = new DrawTracks(e.Graphics, this.drawingScale);

			if (this.placingTrackVisible)
			{
				drawer.drawTrack(this.placingTrack, this.snapOffset);
			}
			if (this.data != null)
			{
				foreach (DataSetLayout.TrackRow row in this.data.Track)
				{
					if (!placingTrackVisible || (placingTrackVisible && this.placingTrack != row))
					{
						drawer.drawTrack(row, this.zeroOffset);
					}
				}
			}
		}

		private void UserControlLayout_MouseLeave(object sender, EventArgs e)
		{
			this.placingTrackVisible = false;
			this.Invalidate();
		}

		private void contextMenuStripRotatePart_Opening(object sender, CancelEventArgs e)
		{
			this.placingTrackFreeze = true;
		}

		private void contextMenuStripRotatePart_Closed(object sender, ToolStripDropDownClosedEventArgs e)
		{
			this.placingTrackFreeze = false;
		}

		private void UserControlLayout_Load(object sender, EventArgs e)
		{

		}

		private void toolStripMenuItem30D_Click(object sender, EventArgs e)
		{
			if (this.placingTrack != null)
			{
				this.placingTrack.rotation += 30;
			}
		}

		private void toolStripMenuItem60D_Click(object sender, EventArgs e)
		{
			if (this.placingTrack != null)
			{
				this.placingTrack.rotation += 60;
			}
		}

		private void toolStripMenuItem90D_Click(object sender, EventArgs e)
		{
			if (this.placingTrack != null)
			{
				this.placingTrack.rotation += 90;
			}
		}

		private void rotateToolStripMenuItemRotate_Click(object sender, EventArgs e)
		{
			if (this.placingTrack != null)
			{
				this.placingTrack.rotation += Convert.ToDouble(this.toolStripTextBoxCustomRotation.Text);
			}
		}

		private void toolStripTextBoxCustomRotation_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				if (this.placingTrack != null)
				{
					this.placingTrack.rotation += Convert.ToDouble(this.toolStripTextBoxCustomRotation.Text);
					this.contextMenuStripRotatePart.Close();
				}
			}
		} 

		#endregion

		private void UserControlLayout_MouseClick(object sender, MouseEventArgs e)
		{
			int trackID;

			if (!this.ready)
			{
				MessageBox.Show("Cannot place Item.\nCanvas not ready", "Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			
			switch (this.selectedTool)
			{
				case Tools.MoveTrack:
					if (this.placingTrack == null)
					{
						trackID = this.snapGrid.moveTrack(e.X * this.drawingScale, e.Y * this.DrawingScale);
						if (trackID == -1)
						{
							return;
						}
						else
						{
							this.placingTrack = this.data.Track.FindByid(trackID);
						}
					}
					else
					{
						this.placingTrack.locationX += this.snapOffset.X;
						this.placingTrack.locationY += this.snapOffset.Y;
						this.placingTrack = null;
						this.placingTrackVisible = false;
						this.snapGrid.clearGrid();
						foreach (DataSetLayout.TrackRow row in this.data.Track)
						{
							this.snapGrid.addTrack(row);
						}
						this.Invalidate();
						return;
					}
					break;

				case Tools.PlacingTrack:
					if (this.placingTrack != null)
					{
						this.placingTrack.locationX += this.snapOffset.X;
						this.placingTrack.locationY += this.snapOffset.Y;
						this.PlacingTrack.id = this.data.Track.Count;
						this.data.Track.AddTrackRow(this.placingTrack);
						this.snapGrid.addTrack(this.placingTrack);
						this.Invalidate();
						if (((TrackType)this.placingTrack.type == TrackType.DoubleSlipSwitch) ||
							((TrackType)this.placingTrack.type == TrackType.TurnoutCurveLeft) ||
							((TrackType)this.placingTrack.type == TrackType.TurnoutCurveRight) ||
							((TrackType)this.placingTrack.type == TrackType.TurnoutStraightLeft) ||
							((TrackType)this.placingTrack.type == TrackType.TurnoutStraightRight))
						{
							UserControlTurnoutController control = new UserControlTurnoutController(1, new Point((int)(this.placingTrack.locationX / this.drawingScale), (int)(this.placingTrack.locationY / this.drawingScale)));
							control.Mode = this.Mode;
							control.deleteControl += new DeleteControl(control_deleteControl);
							this.Controls.Add(control);
						}

						DataSetLayout.TrackRow row = this.placingTrack;
						this.placingTrack = this.data.Track.NewTrackRow();
						switch ((TrackType)(row.type))
						{
							case TrackType.CurveRightR1:
							case TrackType.CurveRightR2:
							case TrackType.CurveRightR3:
							case TrackType.CurveRight:
							case TrackType.CurveRightR2_243:
							case TrackType.CurveLeftR1:
							case TrackType.CurveLeftR2:
							case TrackType.CurveLeftR3:
							case TrackType.CurveLeft:
							case TrackType.CurveLeftR2_243:
								this.placingTrack.radius = row.radius;
								this.placingTrack.angle = row.angle;
								break;
							case TrackType.Straight172:
							case TrackType.Straight188:
							case TrackType.Straight94:
							case TrackType.Straight775:
								this.placingTrack.length = row.length;
								break;
							default:
								break;
						}
						this.placingTrack.rotation = row.rotation;
						this.placingTrack.type = row.type;
						this.placingTrack.locationX = row.locationX;
						this.placingTrack.locationY = row.locationY;

						return;
					}
					break;
				case Tools.Delete:
					trackID = this.snapGrid.moveTrack(e.X * this.drawingScale, e.Y * this.DrawingScale);
					if (trackID == -1)
					{
						break;
					}
					else
					{
						this.data.Track.RemoveTrackRow(this.data.Track.FindByid(trackID));
						this.snapGrid.clearGrid();
						foreach (DataSetLayout.TrackRow row in this.data.Track)
						{
							this.snapGrid.addTrack(row);
						}
						this.Invalidate();
					}
					break;
				case Tools.PlacingControl:
					if (this.currentControl != null)
					{
						if (this.currentControl is IDeleteable) ((IDeleteable)this.currentControl).deleteControl += new DeleteControl(this.control_deleteControl);
						this.currentControl.Location = new Point(e.X, e.Y);
						this.Controls.Add(this.currentControl);
						this.currentControl = null;
						this.SelectedTool = Tools.MoveTrack;
					}
					break;
				default:
					break;
			}
		}

		private Control currentControl;

		public Control CurrentControl
		{
			get { return currentControl; }
			set { currentControl = value; }
		}

		void control_deleteControl(Control control)
		{
			this.Controls.Remove(control);
		}

		private void UserControlLayout_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case Keys.Escape:
					this.SelectedTool = Tools.MoveTrack;
					break;
				default:
					break;
			}
		}
	}
}
